/*
 *  logic.c
 *
 *  Created on: 2010-5-25
 *      Author: liuyond
 *    Abstract: this file will implement the simulation of the following instruction
 *				AND, OR, XOR, TEST, NOT
 */
#include "cpu.h"

void AND_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src & dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src & dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void AND_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src & dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src & dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void AND_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src & dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src & dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void AND_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src & dst;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src & dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void AND_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = src & dst;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void AND_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = src & dst;
	cpu_set_regb(cpu, AX, ret);
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void AND_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src & dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src & dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void AND_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src & dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src & dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void OR_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src | dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src | dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void OR_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src | dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src | dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void OR_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src | dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src | dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void OR_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src | dst;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src | dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void OR_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src | dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src | dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void OR_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src | dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src | dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void OR_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = src | dst;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void OR_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = src | dst;
	cpu_set_regb(cpu, AX, ret);
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void XOR_Eb_Gb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src ^ dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_regb(cpu, i->operand.reg);
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src ^ dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void XOR_Ev_Gv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src ^ dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_reg(cpu, i->operand.reg);
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src ^ dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void XOR_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src ^ dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src ^ dst;
		cpu_set_regb(cpu, i->operand.reg, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void XOR_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src ^ dst;
		cpu_set_reg(cpu, i->operand.reg, ret);
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src ^ dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void XOR_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = src ^ dst;
	cpu_set_regb(cpu, AL, ret);
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void XOR_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = src ^ dst;
	cpu_set_regb(cpu, AX, ret);
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void XOR_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.rm);
		ret = src ^ dst;
		cpu_set_regb(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src ^ dst;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void XOR_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.rm);
		ret = src ^ dst;
		cpu_set_reg(cpu, i->operand.rm, ret);
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src ^ dst;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, ret);
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void TEST_Gb_Eb(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_regb(cpu, i->operand.rm);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src & dst;
	}
	else
	{
		// memory operand
		src = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src & dst;
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void TEST_Gv_Ev(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	if (i->operand.mod == 0x3)
	{
		// register operand
		src = cpu_get_reg(cpu, i->operand.rm);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src & dst;
	}
	else
	{
		// memory operand
		src = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src & dst;
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void TEST_AL_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_regb(cpu, AL);
	ret = src & dst;
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void TEST_AX_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	dst = cpu_get_reg(cpu, AX);
	ret = src & dst;
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void TEST_Eb_Ib(cpu_t *cpu, instruction_t *i)
{
	byte src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_regb(cpu, i->operand.reg);
		ret = src & dst;
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		ret = src & dst;
	}
	cpu_set_flags(cpu, LOG_BYTE, src, dst, ret);
}

void TEST_Ev_Iv(cpu_t *cpu, instruction_t *i)
{
	word src, dst, ret;

	src = i->operand.imm;
	if (i->operand.mod == 0x3)
	{
		// register operand
		dst = cpu_get_reg(cpu, i->operand.reg);
		ret = src & dst;
	}
	else
	{
		// memory operand
		dst = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		ret = src & dst;
	}
	cpu_set_flags(cpu, LOG_WORD, src, dst, ret);
}

void NOT_Eb(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_regb(cpu, i->operand.rm);
		tmp = ~tmp;
		cpu_set_regb(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		tmp = ~tmp;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, tmp);
	}
	// NOT operation don't affect FLAGS register
}

void NOT_Ev(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_reg(cpu, i->operand.rm);
		tmp = ~tmp;
		cpu_set_reg(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		tmp = ~tmp;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, tmp);
	}
	// NOT operation don't affect FLAGS register
}

void NEG_Eb(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_regb(cpu, i->operand.rm);
		tmp = ~tmp + 1;
		cpu_set_regb(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_byte(cpu, i->operand.seg, i->operand.address);
		tmp = ~tmp + 1;
		cpu_set_mem_byte(cpu, i->operand.seg, i->operand.address, tmp);
	}
	// NOT operation don't affect FLAGS register
}

void NEG_Ev(cpu_t *cpu, instruction_t *i)
{
	int tmp;

	if (i->operand.mod == 0x3)
	{
		// register operand
		tmp = cpu_get_reg(cpu, i->operand.rm);
		tmp = ~tmp + 1;
		cpu_set_reg(cpu, i->operand.rm, tmp);
	}
	else
	{
		// memory operand
		tmp = cpu_get_mem_word(cpu, i->operand.seg, i->operand.address);
		tmp = ~tmp + 1;
		cpu_set_mem_word(cpu, i->operand.seg, i->operand.address, tmp);
	}
	// NOT operation don't affect FLAGS register
}

